package com.jmx;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

public class LogReader {

	private static final Logger logger = Logger.getLogger(LogReader.class);
	private static final String FILENAME = "/invoke_times.properties";
	
	public int getTotalTimes(final String queryString) throws LogException {
		int count = 0;
		String value = new PropertiesWrapper(FILENAME).getProperty(queryString);
		if(value != null) {
			count = Integer.parseInt(value);
		}
		return count;
	}
	
	public int getLastMinutesTimes(final String queryString, Date startTime) throws LogException {
		//1 Get log file
		//2 loop log file
		//3 Get log file and start time mapping
		//4 Get flag
		//5 loop log file
		
		/*Re-factor idea(work flow):
		 * Create Step and Engine
		 * Register the five step to Step
		 * Configure business flow in xml file
		 * Execute engine(engine will combine each Step and xml file)
		 * */
		int count = 0;
		int flag = 0;
		String date = "";
		Map<String, Date> map = null;
		try{
			map = getFileAndStartTime();
		} catch(Exception ex) {
			logger.error(ex.getMessage());
			throw new LogException(ex.getMessage());
		}
		Entry<String, Date>[] entries = sort(map);
		flag = getStartFile(entries, startTime);
		for(int i = flag; i < entries.length; i++) {
			BufferedReader in = null;
			try {
				in = new BufferedReader(new FileReader(entries[i].getKey()));
				String line = "";
				while ((line = in.readLine()) != null) {
					date = getTimeFromLine(line);
					if(date != null && !date.isEmpty() && !startTime.after(stringToDate(date)) && line.contains(queryString)) {
						count++;
					}
				}
			} catch(Exception ex) {
				logger.error(ex.getMessage());
				throw new LogException(ex.getMessage());
			} finally {
				if(in != null) {
					try{
						in.close();
					} catch(IOException ex) {
						logger.error(ex.getMessage());
						throw new LogException(ex.getMessage());
					}
				}
			}
		}
		return count;
	}
	
	private String[] getLogFile(String pathname) throws LogException {
		List<String> list = new ArrayList<String>();
		File logDirectory = new File(pathname);
		if(logDirectory.isDirectory()) {
			File[] files = logDirectory.listFiles(new FilenameFilter() {
				
				@Override
				public boolean accept(File dir, String name) {
					if(name.contains(".log")) {
						return true;
					}
					return false;
				}
			});
			for(File file : files) {
				if(file.isFile()) {
					list.add(file.getAbsolutePath());
				} else {
					logger.info("File: " + file.getName() + " is not a log file.");
				}
			}
			return list.toArray(new String[list.size()]);
		} else {
			throw new LogException("File: " + pathname + " is not a directory.");
		}
	}
	
	private String getPathName() {
		return "C:\\log";
	}
	
	private Map<String, Date> getFileAndStartTime() throws LogException, FileNotFoundException, ParseException {
		String date = "";
		Map<String, Date> map = new HashMap<String, Date>();
		String[] logFiles = getLogFile(getPathName());
		for(String file : logFiles) {
			BufferedReader in = null;
			try{
				in = new BufferedReader(new FileReader(file));
				String line = "";
				while ((line = in.readLine()) != null) {
					date = getTimeFromLine(line);
					if(date != null && !date.isEmpty()) {
						map.put(file, stringToDate(date));
						break;
					}
				}
			} catch(IOException ex) {
				logger.error(ex.getMessage());
				throw new LogException(ex.getMessage());
			} finally {
				if(in != null) {
					try{
						in.close();
					} catch(IOException ex) {
						logger.error(ex.getMessage());
						throw new LogException(ex.getMessage());
					}
				}
			}
		}
		return map;
	}
	
	private Date stringToDate(String str) throws ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
		return sdf.parse(str);
	}
	
	private String getTimeFromLine(String line) {
		String date = "";
		Pattern pattern = Pattern.compile("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2},\\d+");
		Matcher matchers = pattern.matcher(line);
		if(matchers.find()) {
			date = matchers.group();
		}
		return date;
	}
	
	private int getStartFile(Entry<String, Date>[] entries, Date startTime) {
		int flag = 0;
		for(int i = 0; i < entries.length; i++) {
			if(startTime.after(entries[i].getValue())) {
				if(i == entries.length - 1) {
					flag = entries.length - 1;
				}
				continue;
			} else {
				flag = i - 1;
				break;
			}
		}
		if(flag < 0) {
			flag = 0;
		}
		return flag;
	}
	
	private Entry<String, Date>[] sort(Map<String, Date> map) {
		@SuppressWarnings("unchecked")
		Entry<String, Date>[] entries = map.entrySet().toArray(
				new Entry[map.entrySet().size()]);
		Comparator<Entry<String, Date>> comparator = new Comparator<Entry<String, Date>>() {
			@Override
			public int compare(Entry<String, Date> entry1,
					Entry<String, Date> entry2) {
				if (entry1.getValue().after(entry2.getValue())) {
					return 1;
				} else if (entry1.getValue().after(entry2.getValue())) {
					return -1;
				} else {
					int num1 = getNumber(entry1.getKey());
					int num2 = getNumber(entry2.getKey());
					if (num1 < num2) {
						return 1;
					} else if (num1 > num2) {
						return -1;
					} else {
						return 0;
					}
				}
			}
		};
		Arrays.sort(entries, comparator);
		return entries;

	}
	
	private int getNumber(String str) {
		int number = 999;
		if(str != null && !str.isEmpty() && str.lastIndexOf(".") > 0) {
			String num = str.substring(str.lastIndexOf("."));
			if(num != null && num.matches("\\d+")) {
				number = Integer.parseInt(num);
			}
		}
		return number;
	}
	
	
	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		LogReader logReader = new LogReader();
		//System.out.println(logReader.getTotalTimes("com.jmx.HelloWorld"));
		long start = System.currentTimeMillis();
		System.out.println(logReader.getLastMinutesTimes("End invoke service com.security.dpi.bds.helloworld.service.impl.HelloWorldExposeServiceImpl.hello", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS").parse("2012-06-12 15:50:58,706")));
		System.out.println((System.currentTimeMillis() - start)/1000);
		/*SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
		Map<String, Date> map = new HashMap<String, Date>();
		map.put("test", format.parse("2012-06-15 15:50:57,987"));
		map.put("test.1", format.parse("2012-06-14 15:50:57,987"));
		map.put("test.2", format.parse("2012-06-14 15:50:57,987"));
		Entry<String, Date>[] entries = logReader.sort(map);
		int flag = logReader.getStartFile(entries, format.parse("2012-06-16 15:50:57,987"));
		System.out.println(flag);*/
		
	}

}
